package org.liang.email4j.submail;

import java.io.File;
import java.util.TreeMap;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSONObject;

/**
 * A class extends TreeMap in order to store the request data with format of key-value. Such as
 * appid, appkey, to and other information.The TreeMap ensure that the key can be sorted descending
 * to create signature.
 * 
 * @version 1.0 2014/11/2
 */
public class RequestData extends TreeMap<String, Object> {

    private static final long serialVersionUID = -978566326488674858L;

    private static final String COMMA = ",";
    private static final String TO = "to";
    private static final String FROM = "from";
    private static final String FROM_NAME = "from_name";
    private static final String REPLY = "reply";
    private static final String CC = "cc";
    private static final String BCC = "bcc";
    private static final String SUBJECT = "subject";
    private static final String TEXT = "text";
    private static final String HTML = "html";
    private static final String ATTACHMENTS = "attachments";
    private static final String HEADERS = "headers";

    RequestData() {}

    void addTo(String address, String name) {
        addWithBracket(TO, name, address);
    }

    void setFrom(String sender, String name) {
        put(FROM, sender);
        put(FROM_NAME, name);
    }

    void setReply(String reply) {
        put(REPLY, reply);
    }

    void addCc(String address, String name) {
        addWithBracket(CC, name, address);
    }

    void addBcc(String address, String name) {
        addWithBracket(BCC, name, address);
    }

    void setSubject(String subject) {
        put(SUBJECT, subject);
    }

    void setText(String text) {
        put(TEXT, text);
    }

    void setHtml(String html) {
        put(HTML, html);
    }

    void addAttachment(String file) {
        addWithIncrease(ATTACHMENTS, new File(file));
    }

    void addHeaders(String key, String val) {
        addWithJson(HEADERS, key, val);
    }

    /**
     * Define a adding pattern that data can be added to map one by one but displayed with a string
     * separated by comma. For Example, <code> 
     * addWithComma("K", "v1");
     * addWithComma("K", "v2");
     * </code> Then, the map is {"K", "v1, v2"}
     * 
     * @param key
     *            is the map's key
     * @param value
     *            is the adding data
     */
    private void addWithComma(String key, String value) {
        if (StringUtils.isEmpty(key))
            return;
        if (this.containsKey(key)) {
            String item = COMMA + value;
            this.put(key, this.get(key) + item);
        } else {
            this.put(key, value);
        }
    }

    /**
     * Define a adding pattern that data can be added to map one by one but displayed with a string
     * decorated by angle brackets. For Example, 
     * addWithBracket("K", "v11", "v12");
     * addWithBracket("K", "v21", "v22");
     *<code> Then, the map is {"K", "v11:v12, v21:v22"}</code>
     * 
     * 
     * @param key
     *            is the map's key
     * @param left left value
     * @param right right value
     */
    private void addWithBracket(String key, String left, String right) {
        addWithComma(key, left + "<" + right + ">");
    }

    /**
     * Define a adding pattern that data can be added to map one by one but displayed with a json.
     * For Example, <code> 
     * addWithBracket("K", "jk1", "jv1");
     * addWithBracket("K", "jk2", "jv2");
     * </code> Then, the map is {"K",{"jk1":"jv1","jk2":"jv2"}
     * 
     * @param key
     *            is the map's key
     * @param jKey
     *            is the key of json
     * @param jValue
     *            is the value of json
     */
    private void addWithJson(String key, String jKey, String jValue) {
        if (StringUtils.isEmpty(key))
            return;
        try {
            JSONObject json = null;
            if (this.containsKey(key)) {
                Object val = this.get(key);
                json = JSONObject.parseObject(val.toString());
            } else {
                json = new JSONObject();
            }
            if (json != null) {
                json.put(jKey, jValue);
                this.put(key, json.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private int idx = 0;

    /**
     * Put a data with increasing key. For exmaple,
     * <code>addWithIncrease("K", "v1");addWithIncrease("K", "v2");
     * </code> Then, the map is {"K[0]", v1},{"K[1]", v2}
     * 
     * @param key
     *            is the map's key
     * @param value
     *            is the map's value
     */
    private void addWithIncrease(String key, Object value) {
        this.put(key + "[" + idx++ + "]", value);
    }
}
